/*
 * Copyright (c) 2006-2021, Ulandlink Development Team
 * SPDX-License-Identifier: Apache-2.0
 * Change Logs:
 * Date           Author       Notes
 * 2021-12-06      zkw		first version
 */

#include <rtthread.h>
#include <librws.h>
#include <string.h>
#include <stdlib.h>
#include "app_ocpp_mgnt_msg.h"
#include "app_websocket_mgnt_mp.h"
#include "app_websocket_mgnt_util.h"
#include "app_websocket_ocpp_drv.h"
#include "app_sys_param.h"
#include <app_charge_param.h>
#include "app_network_param.h"

#define LOG_TAG "ocpp.websocket.util"
#define LOG_LVL LOG_LVL_INFO
#include "ulog.h"

#ifdef LIBRWS_USING_MBED_TLS
const char ampup_certificate[] =
    "-----BEGIN CERTIFICATE-----\r\n"
    "MIINIjCCDAqgAwIBAgIRAN77MUflHHgACQAAAADy7qYwDQYJKoZIhvcNAQELBQAw\r\n"
    "RjELMAkGA1UEBhMCVVMxIjAgBgNVBAoTGUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBM\r\n"
    "TEMxEzARBgNVBAMTCkdUUyBDQSAxRDQwHhcNMjIwMTA0MDI1MTI0WhcNMjIwNDA0\r\n"
    "MDI1MTIzWjAqMSgwJgYDVQQDEx9pbnNlbnQtZm9ybXMtdGVzdC11cmwuaW5zZW50\r\n"
    "LmFpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0iA4+dUKWgMscjCw\r\n"
    "eisweg4/A08uxrfHKNwGnA6/z+ON7ZytWaAgvx+q+ESqggfVOY68YgsEiTnHoDhp\r\n"
    "ggrWrb62Cf/HBei6zD4wuJACFRM4KtSKWHIFsj9jLYaqaWiIm/Cz4ofs51wSAixI\r\n"
    "89llhMA9p+/Uiat7X3Y3nYhrfxfBQ4JRT6jn5O98c8qv2MsCW3ZNTob5WR6WJxBS\r\n"
    "2QWk//tVMMjOThi69wah13bIFcgl3pBlD/yuRC0J991TqWV9CYgV1yU1tsh49CEX\r\n"
    "ZD82jXqtE4UCUJ2VR4GwrRhcpoaxzcOrhTyEPnYlHL2LnEbQ2JJKRdGMOegOsVdl\r\n"
    "c3e+gQIDAQABo4IKJTCCCiEwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsG\r\n"
    "AQUFBwMBMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAap3NkUPVD1G5jttt0R570W\r\n"
    "twz8MB8GA1UdIwQYMBaAFCXiGA6yV5GUKuXUXYaQg95Ts7iSMGoGCCsGAQUFBwEB\r\n"
    "BF4wXDAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWQ0MDEG\r\n"
    "CCsGAQUFBzAChiVodHRwOi8vcGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxZDQuZGVy\r\n"
    "MIIH1gYDVR0RBIIHzTCCB8mCH2luc2VudC1mb3Jtcy10ZXN0LXVybC5pbnNlbnQu\r\n"
    "YWmCCWlncm9zLmFwcIINdHJlbmR3ZWxsLmFwcIIWd3d3LnNjcmlwdHVyZXVuaW9u\r\n"
    "LmFwcIIbZnJhbmtsaW5maXJzdC5xYS53YWxsaXQuYXBwgg1iYXVtYW5uLmNvZGVz\r\n"
    "ghRhcm1lbmlhbi1sYXd5ZXJzLmNvbYIYd3d3LnBzeWNob2xvZ2llLW1hcmljLmF0\r\n"
    "gg1ib3VjaGVycGwuY29tgg9jb21wbGljYXRpby5jb22CF2NyLXN0YWdpbmcuY29k\r\n"
    "ZXdhcnMuY29tghZ3d3cuY29sb3Jzc29mdHdhcmUuY29tghh3d3cubGF1ZGlyaW1v\r\n"
    "dmVpcy5jb20uYnKCEHd3dy5iZWxnZWZlc3QuYnmCEWFwcC5jYWxlbmRheXMuY29t\r\n"
    "ghRtZXRhdW1sLmRlbmtzb2Z0LmNvbYIVbWlhLmFwcDIuMW9uMW5hdmkuY29tgg5n\r\n"
    "YWNoaWdhbWVzLmNvbYITb3NjYXIucHJ1ZWJhLmNvbS5hcoIMZ29nb2RvZ2UuY29t\r\n"
    "ggtmYXJoY29tLmNvbYIUa2l0Y2hlbnBhcnRuZXJpZC5jb22CEWxvb2t1cGxpc3Rp\r\n"
    "bmcuY29tghpzdXBwb3J0Lm1hbnVzY3JpcHRzYXBwLmNvbYIKbWVzaG9zLmNvbYIb\r\n"
    "bW9ycmhlYXR3YXN0ZW9pbGJvaWxlcnMuY29tghR3d3cubWVkcHJlcG5lcGFsLmNv\r\n"
    "bYINbWlnc3ZhcHBzLmNvbYIVdGllbmRhLm1pcGFwZWxlcmEuY29tghJteWdvb2Rj\r\n"
    "YWxvcmllcy5jb22CE3d3dy5teWVxdXVzdGVhbS5jb22CDnd3dy5uZWFycGUuY29t\r\n"
    "ghBtb3Nwcm9kdmlkZW8uY29tgiB3b3JraW5nc3RhdHVzLm9uZWJyaWdodHNwYWNl\r\n"
    "LmNvbYIVcGxheXNwYWRlcy1vbmxpbmUuY29tghJwcm9ncmFtb2JzY3VyYS5jb22C\r\n"
    "EXd3dy5yb25hbmR2aXYuY29tghd3d3cub3V0c291cmNlY29kZXJzLmNvbYIUd3d3\r\n"
    "LnNhaGluLWluc2FhdC5jb22CDXNwb3R5YmV0cy5jb22CGWFscGhhLmRvbWUucm91\r\n"
    "bmQtemVyby5jb22CF2ZvcnR1bmVhcHAuc2lwYW5vdGUuY29tggpza3l6ZXguY29t\r\n"
    "gg5zdHVmZnV3aXNoLmNvbYIYYnJva2VyLnN1cGVyZGlzcGF0Y2guY29tghV1bml2\r\n"
    "ZXJzYWxjdWlzaW5lcy5jb22CFXZvdHJvbmVuZ2luZWVyaW5nLmNvbYINd3d3LmRl\r\n"
    "dmlpLmRldoITd3d3LnZ5c2huZXZza3lpLmRldoIVc3RhZ2Utc2Nhbi56a3N5bmMu\r\n"
    "ZGV2ghF3d3cuaG9zZW5sb3Nlci5kZYIJaXR1bGFuLmRrghNtYXN0ZXIucXVhbGl0\r\n"
    "eXVwLmVzghF0dXJpbmdjb21wbGV0ZS5mbYIKc3dpcGVpdC5maYIPc3cudGFzZ2xv\r\n"
    "YmFsLmV1ghB3d3cuYnVnZHJpdmVuLmVlghB3d3cuY2FsbWluZGVyLmV1ggd1cmJ6\r\n"
    "LmV1ghdrYXJub3R0LnRob21hc2dyaXZldC5mcoIJbWludHRyLmlughNzb3JyeS50\r\n"
    "ZWFtZHJ0LmNvLmlugiVhdGhhbmFzaW9zZWZ0aHltaW91LWluc3VyYW5jZWdyb3Vw\r\n"
    "Lmdyght4cGxvcmVlZ2FtZXMuaHVudGVyZ2FtZXMuaW6CD3N0ZWVsd2luZG93cy5p\r\n"
    "ZYIZbGlua3MuZW50cmVwcmVuZXVyLXplbi5mcoIVd3d3Lm5wYWNvbnN1bHRhbnRz\r\n"
    "LmluggdzYW43LmlughJzaW1vbnlpdXRpb3ZvZGEuaHWCE2xhbmRpbmcuY2hla2Vy\r\n"
    "LmluZm+CFXd3dy5kZXVyaXZhc3F1ZXouaW5mb4ISam9zaHVhYmxha2xleS5pbmZv\r\n"
    "ghRvY3BwLWNsaWVudC5hbXB1cC5pb4IPd3d3Lm1pbmhkby5pbmZvghBwb3J0YWwu\r\n"
    "bndwbHVzLmlvghN3d3cucGxheWFuZGxlYXJuLmlvgg9wbGF5YW5kbGVhcm4uaW+C\r\n"
    "E3d3dy5iaWdnZXJnYW1lcy5uZXSCD3d3dy5idGNub3cubGl2ZYISZGV2LmFkbWlu\r\n"
    "LmRpcHBhLmpwggtteWZ1bi5wYXJ0eYILZzRtZS5zdHVkaW+CDXd3dy5rcm9udXMu\r\n"
    "aXSCFmltYWdlLWNvbnZlcnRlci5vbmxpbmWCEGRldi5tZWFzdXJlLnRlYW2CF2xl\r\n"
    "cm1hLndpZmlncmF0aXMuY29tLm14ghN3d3cubHlvbi50ZWNobm9sb2d5ggtiYXJn\r\n"
    "bWFubi5pb4IJNjNyZWQuYXBwghJ3d3cuYW5keWNvb2suY28udWuCEGltZGIud3Jl\r\n"
    "aWYuY28udWuCGm1pbmVzd2VlcGVyLmZpbGlwd2VpbGlkLnNlggxhd2VpZ2guY28u\r\n"
    "dWuCFHNoYXJlLnBldHBhcmVudHMuYXBwghR3d3cuYnVja2xlcmFzaC5jby51a4IV\r\n"
    "c3VubW9vbi15b2dhLnBocm9zLmNhggpwb29waW5nLmNvghN3d3cudmFyc2l0eWhx\r\n"
    "LmNvLnphgglpY3BsdXMuY2yCF3JlZ2lzdGVyLmRlbGJlLnNraXByLmNvMCEGA1Ud\r\n"
    "IAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYDVR0fBDUwMzAxoC+gLYYr\r\n"
    "aHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWQ0L1M5dlRKY1dNVlIwLmNybDCCAQMG\r\n"
    "CisGAQQB1nkCBAIEgfQEgfEA7wB2ACl5vvCeOTkh8FZzn2Old+W+V32cYAr4+U1d\r\n"
    "JlwlXceEAAABfiM8KZcAAAQDAEcwRQIgQ7ZeL2ArcgctY3IvvbZPt6TbQtIh7Qwc\r\n"
    "TC6x/iMpAxQCIQD4LdOX7eUzJAU/kaYKGvKVZi9lh+t2H7cCWgKXEs3ptQB1AFGj\r\n"
    "sPX9AXmcVm24N3iPDKR6zBsny/eeiEKaDf7UiwXlAAABfiM8KZEAAAQDAEYwRAIg\r\n"
    "DajEFUxXHWTLAquSq5sJwv+HFPNt9i2zw7laHCsJqxICIEkC+UXLAOKNKsMhVfNP\r\n"
    "hCYATySIJ185m7m9RzkQiHKdMA0GCSqGSIb3DQEBCwUAA4IBAQAipdXHL9GcUoYe\r\n"
    "8bxn3ouN6f/9Y1UH2zTwbnuUiCMQUBPOB24ymtvP6GTqgAUzK3fnTSc0smyxn7y5\r\n"
    "HpDFGcTW8jekSdfLa8KMwnq4OeF1kT5CuQvG3tV1WDncIUtJMNgUSNg7RsG12CUF\r\n"
    "63w4SIEg/wj9sis2RdLbwFQXYQyNsxq+soO2477o8dwBv9bRhbQE86GdVg3jOr0O\r\n"
    "K6u5qv03xQkC9IKbwBRXkgJJyuCEYkuT98G/P3MpRuE3xP4Fk6dyF6CR0dqrscjx\r\n"
    "5/sZzRNvjKoeN8+gS5nZWOTtm7jktFFwJ1OJqkquODvmn7M04QdDOEvG4dquRPDr\r\n"
    "WtIBT+Uc\r\n"
    "-----END CERTIFICATE-----\r\n";
#endif

#define RECV_PAYLOAD_BUFF (2048)
// struct librws_app
struct librws_app {
    rt_bool_t init;     // websocket conn flag
    rws_socket *socket; // socket
    char *recv_payload; // 接收数据的buff
};

static struct librws_app librws =
    {
        .init = RT_FALSE,
        .socket = RT_NULL,
        .recv_payload = RT_NULL};

static void app_webclient_clr_librws(void) {
    librws.init = RT_FALSE;
    librws.socket = RT_NULL;
    if (librws.recv_payload) {
        rt_free(librws.recv_payload);
        librws.recv_payload = RT_NULL;
    }
}

// 连接到服务器成功，post给ocpp_mngt
static void app_webclient_on_open(rws_socket socket) {
    struct app_ocpp_msg_websocket_data msg_data;
    msg_data.web_conf_type = E_OCPP_CONNECT;
    msg_data.status = true;
    app_ocpp_mgnt_websocket_msg_post(&msg_data);
    LOG_I("websocket connected. ");
}

// 服务端断开websocket连接
static void app_webclient_on_close(rws_socket socket) {
    struct app_ocpp_msg_websocket_data msg_data;
    rws_error error = rws_socket_get_error(socket);
    if (error) {
        LOG_E("websocket disconnect, error: %i, %s ", rws_error_get_code(error), rws_error_get_description(error));
    } else {
        LOG_W("websocket disconnect! ");
    }
    rws_socket_disconnect_and_release(librws.socket);
    app_webclient_clr_librws();

    msg_data.web_conf_type = E_OCPP_CONNECT;
    msg_data.status = false;
    app_ocpp_mgnt_websocket_msg_post(&msg_data);
}

// 收到服务端的消息
static void app_webclient_recv_text(rws_socket socket, char *text, const unsigned int len) {
    const char *recv = text;
    app_websocket_recv_msg_data_t recv_data = {0};
    int call = 0;
    if (len <= 0) {
        return;
    }

    recv_data.payload = librws.recv_payload;
    if (recv_data.payload == RT_NULL) {
        return;
    }

    if (recv) {
        LOG_I("Recv << %.*s", len, recv);
    }

    recv_data.web_msg_type = atoi(&recv[1]);

    if (recv_data.web_msg_type == E_OCPP_MESSAGE_CALL) {
        /* [2,"61d7f","ChangeConfiguration",{"key":"MeterValuesSampledData","value":"Voltage,Temperature"}] */
        sscanf(recv, "[%d,\"%[^\"]\",\"%[^\"]\",%[^\n]", &call, recv_data.ocpp_uid, recv_data.ocpp_action, recv_data.payload);
        LOG_D("action:%s", recv_data.ocpp_action);
    } else if (recv_data.web_msg_type == E_OCPP_MESSAGE_CALL_RESULT) {
        /* [3,"1",{"status":"Accepted","currentTime":"2022-01-07T08:01:14Z","interval":60}] */
        sscanf(recv, "[%d,\"%[^\"]\",%[^\n]", &call, recv_data.ocpp_uid, recv_data.payload);
    } else {
        goto exit;
    }
    app_webclient_recv_data_msg_post(&recv_data);
exit:
    return;
}

static void app_webclient_recv_bin(rws_socket socket, const void *data, const unsigned int len) {
    char *buff = RT_NULL;

    buff = (char *)rt_malloc(2048);

    rt_memset(buff, 0x00, 2048);
    rt_memcpy(buff, data, len);

    LOG_D("message(bin), %d(byte): %s ", len, buff);

    if (buff != RT_NULL) {
        rt_free(buff);
    }
}

// websocket连接
int app_webclient_util_conn(void) {
    struct ocpp_server_param server = {0};
    char dev_sn[SYS_DEV_SN_LEN] = {'\0'};
    char str_buff[SYS_DEV_SN_LEN + OCPP_PATH_LEN] = {0};

    uint16_t web_server_port = 0;
    uint8_t dev_type;

    bool ret = rws_false;
    if (librws.init == RT_TRUE) {
        LOG_W("the websocket connection has been opened. ");
        goto _exit;
    }
    /* 获取设备类型和OCPP服务器参数 */
    app_charge_param_get(SYS_CHARGE_MODE, &dev_type, sizeof(dev_type));
    if (dev_type != SYS_DEV_TYPE_OCPP) {
        LOG_E("the Charge Point type error.");
        goto _exit;
    }

    if (app_network_param_get(NETWORK_OCPP, &server, sizeof(server)) != TRUE) {
        LOG_E("get ocpp param error.");
        goto _exit;
    }

    if (app_sys_param_get(APP_SYS_PARAM_SN, dev_sn, sizeof(dev_sn)) != TRUE) {
        LOG_E("get Charge Point SerialNumber error.");
        goto _exit;
    }

    librws.socket = rws_socket_create();
    if (librws.socket == RT_NULL) {
        LOG_E("librws socket create failed.");
        goto _exit;
    }
    /* 设置scheme */
    rws_socket_set_scheme(librws.socket, server.server_scheme);

    /* 设置域名*/
    rws_socket_set_host(librws.socket, server.server_host);

    /* 设置端口号 */
    rws_socket_set_port(librws.socket, server.server_port);

    /* 设置域名服务器所在的路径 */
    rt_snprintf(str_buff, sizeof(str_buff), "%.*s%.*s",
                rt_strlen(server.server_path), server.server_path,
                rt_strlen(dev_sn), dev_sn);
    rws_socket_set_path(librws.socket, str_buff);

/* 设置证书 */
#ifdef LIBRWS_USING_MBED_TLS
    rws_socket_set_server_cert(librws.socket, ampup_certificate, sizeof(ampup_certificate));
#endif

    rws_socket_set_on_connected(librws.socket, &app_webclient_on_open);
    rws_socket_set_on_disconnected(librws.socket, &app_webclient_on_close);
    rws_socket_set_on_received_text(librws.socket, &app_webclient_recv_text);

    rws_socket_set_custom_mode(librws.socket);

    ret = rws_socket_connect(librws.socket);
    LOG_D("websocket connect result is (%d)", ret);

    if (librws.recv_payload == RT_NULL) {
        librws.recv_payload = (char *)rt_calloc(1, RECV_PAYLOAD_BUFF);
        if (librws.recv_payload == RT_NULL) {
            ret = rws_false;
            goto _exit;
        }
    }

_exit:
    if (ret) {
        librws.init = RT_TRUE;
    } else {
        rws_socket_disconnect_and_release(librws.socket);
        app_webclient_clr_librws();
    }
    return ret;
}

// 发送数据
bool app_webclient_util_send(const char *text, int32_t len) {
    bool ret = false;

    if (librws.init == RT_FALSE) {
        LOG_W("websocket connection is err ");
        return ret;
    }

    ret = rws_socket_send_text(librws.socket, text);

    if (ret) {
        LOG_I("Send >> %.*s", len, text);
    }

    return ret;
}

// 关闭连接
bool app_webclient_util_close(void) {
    if (librws.init == RT_TRUE) {
        rws_socket_disconnect_and_release(librws.socket);
        app_webclient_clr_librws();
        LOG_I("try disconnect websocket connection. ");
    }

    return true;
}
